第13节 Es6新特性
ES6介绍
阮一峰es6文档地址: https://es6.ruanyifeng.com/
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了也叫ECMAScript 2015。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言
(一) let 命令和const命令
知识点:
let的用法类似于var,用于变量的声明
使用let就会产生块级作用域, let命令只在块级作用域内(也就是大括号内)有效
let在同一作用域内只能声明一次, 不能重复声明
let和const不存在变量提升
详细例子:
1. let命令
// 用let声明变量
<script>
let username = '张十三';
let age = 100;
</script>
// 用let声明的变量有块级作用域
// es5没有块级作用域
{
var i = 0;
}
console.log('i',i);
// es6有块级作用域
{
// 用let声明的变量, 只在括号内有效
let j = 1;
console.log('{}',j);
}
// 用let声明的变量,在括号外无效, 所以报错
console.log('j',j);
// 解决for循环问题
for (var i=0;i<5;i++) {
// todo
}
console.log('i',i);
// 用let声明的变量j是局部变量
for(let j=0;j<5;j++) {
setTimeout(function() {
console.log(j);
},1000)
}
2. const命令
- 用来声明常量
- 不能被重新赋值
- 若是对象, 可以修改属性, 但不能重新赋值
const PI = 3.141592653519383447;
// PI = 100; // 会报错,因为常量不能被重新赋值
const obj = {
username: 'zs',
age:18
}
//obj = {}; // 会报错,不可以重新赋值
// 用const声明的对象可以修改属性
obj.username = 'lisi';
console.log(obj);
3.不能重复声明
var username = 'zs';
var username = 'lisi';
let age = 20;
// 报错 Identifier 'age' has already been declared
let age = 30;
4. let和const声明不会提前
console.log(username); // es5:变量提前,值为undefined
console.log(age); // es6:变量声明不会提前, 所以报错
var username = "zs";
let age = 20;
5.var、let、const 区别(背诵)
var 关键字的特点:
- 变量(预解析)提升,可以在声明的前面使用
- 同一作用域内可以多次声明同一个变量(即便这种方式不建议这样去写)
- 能让它形成作用域的只有函数
let:声明变量的关键字
- 没有变量提升,只能在声明之后使用
- 同一作用域内只能声明一次
- 你声明的变量的作用域仅限于最近的花括号内( {} )
const:只能用来声明常量,该常量一旦声明其值就不能改变( 与let的唯一区别 )
- 没有变量提升,只能在声明之后使用
- 同一作用域内只能声明一次
- 你声明的变量的作用域仅限于最近的花括号内( {} )
- 用const声明的变量: 不允许重新赋值,引用数据类型可以添加或修改属性
(二) 变量的解构赋值
知识点:
解构: 结构分解, 从一个整体的变量里分解出一部分来使用
数组解构
对象解构
函数参数解构和默认值
<script>
//数组解构
let arr = ['a','b','c'];
// 对arr进行结构
let [x,y,z] = arr;
console.log(x);
console.log(y);
console.log(z);
//对象解构
let obj = {
age: 100,
username:'张三',
addr: '广东'
}
// 对象结构,对象是无序的,所以顺序无所谓
let {username,age,addr} = obj;
console.log(username);
</script>
// 2.在函数中使用解构
// 自动结构: let {name,age} = obj;
function say({name,age}) {
console.log(name);
console.log(age);
}
let obj = {
name: 'zs',
age:18
}
say(obj);
// 3.默认值(1)
function say(obj) {
console.log(obj.name);
}
let obj = {
name: "zs",
age: 18,
};
// say(obj); // 正常操作
say(); // 因为没有传对象,所以obj的值为undefined, console.log(obj.name) 就相当于console.log(undefined.name); 会报错
// 对象设置默认值,obj默认为{}
function say(obj={}) {
console.log(obj.name);
}
let obj = {
name: "zs",
age: 18,
};
say();
// 4.对象属性设置默认值(2)
function say({name='老胡',age=100}) {
console.log(name);
console.log(age);
}
let obj = {
name: "zs",
age: 18,
};
say({}); // 必须传入{}, 如果不传,函数参数无法解构,会报错
// 5.对象和属性都设置默认值
function say({name='老胡',age=18}={}) {
console.log(name);
console.log(age);
}
let obj = {
name: "zs",
age: 18,
};
say();
(三) 模板字符串
<!DOCTYPE html>
<html lang="en">
<body>
<script>
let username = '老张';
let age = 100;
// let str = '他叫'+username+',他老了';
let str = `他叫${username},他${age}了`;
let htmlStr = `<ul>
<li>${username}</li>
<li>${age}</li>
</ul>`;
console.log(htmlStr);
</script>
</body>
</html>
(四) 对象的扩展
也就是对象的一些新特性
知识点:
属性和方法的简洁表示法
变量做属性名
合并对象
1.属性和方法的简洁表示法
let username = '张三';
let age = 20;
// es5对象的写法
const obj = {
username: username,
age: age,
say: function() {
console.log(this.username);
}
}
// es6对象属性和对象的简洁表示方式
const obj2 = {
// 如果属性和值相同,只写一个
username,
age,
say() {
console.log(this.username);
}
}
2.变量做属性名
let key = "username";
const obj = {
// [key]使用变量
[key]: "222",
aaa: "333",
};
console.log(obj);
3.合并对象
let obj1 = {
name: 'zs',
age: 20
}
let obj2 = {
name: '李四',
age: 20,
addr: '广东深圳'
}
const obj = Object.assign(obj1,obj2);
console.log(obj);
// 合并数组
let arr1 = [1,2,3];
let arr2 = [4,5,6];
let arr = arr1.concat(arr2);
console.log(arr);
(五) 函数的扩展: 箭头函数
知识点
箭头函数的常见表达方式
箭头函数的this指向
箭头函数不能做构造函数
箭头函数的arguments对象不可用
1. 箭头函数的常见表达方式
// 表达方式1
// 箭头函数
const add = (a,b)=> {
return a+b;
}
add(2,3);
// 表达方式2: 箭头函数的简写方式
- 函数体只有一行的时候,可以简写成
- 上面的例子可以简写成下面的代码
const add = (a, b) => a + b;
add(2, 3);
const arr = [1, 2, 3, 41, 2, 34, 4, 12];
// es5写法
arr.filter(function (item) {
return item > 20;
});
// 箭头函数的写法
arr.filter((item) => item > 20);
// 表达方式3: 参数只有一个
arr.filter(item => item > 20);
2. 箭头函数的this指向
- 箭头函数自己是没有this的, 它会捕获它的上下文(作用域), 作为它自己的this
- 从现象上看就是箭头函数的外面this指向谁, 它的this就指向谁
const obj = {
say() {
// this指向obj
console.log('1',this);
setTimeout(function(){
// 匿名函数,this指向window
console.log('2',this);
},1000)
setTimeout(()=>{
// 匿名函数,this指向window
console.log('3',this);
},2000)
}
}
obj.say();
3. 箭头函数不能做构造函数
箭头函数本身没有this, 所以不能拿来做构造函数的
const Person = (name,age)=> {
this.name = name;
this.age = age;
}
const p = new Person();
4. 箭头函数的arguments对象
- 在浏览器环境下arguments对象不可用
- 在nodejs环境下, arguments对象可以用
const say = () => {
console.log('对象',arguments);
}
say(1,2,3);
(六) 数组的扩展
知识点:
- Array.from() // 将伪数组(类数组)变成真数组
- find() // 找到了就返回符合条件的成员, 找不着就返回undefined
- findIndex() // 找到了就返回符合条件的成员的下标, 找不着就返回-1
- includes() // 判断数组是否包含某个成员, 只能对数组成员是基本数据类型的数组使用
- some() // 判断数组是否包含某个成员
- keys() // 遍历键, 了解
- values() // 遍历值, 了解
- entries() // 遍历键值对, 了解
1. Array.from()
将伪数组(类数组)变成真数组
// itemList是一个伪数组,不是真的
let itemList = document.querySelectorAll('.item');
Array.isArray(itemList); // false
let list = Array.from(Array);
Array.isArray(list); // true
// arguments对象,函数调用时都会产生的一个对象, 用来存放所有实体参数
function say() {
console.log(Array.isArray(arguments)); //false arguments是个伪数组
let args = Array.from(arguments);
console.log(Array.isArray(args)); // true
}
say('a','b','c');
2. find()
找到了就返回符合条件的成员, 找不着就返回undefined
let list = [
{ username: "zs", age: 21 },
{ username: "lisi", age: 20 },
{ username: "ww", age: 22 },
{ username: "lisi", age: 100 },
];
let res1 = list.find(function(item) {
return item.username === 'lisi';
})
console.log('res1',res1);
let res2 = list.find(function(item) {
return item.username === 'lisan';
})
console.log('res2',res2);
详细例子
// 1.Array.from
<script>
</script>
// 2.find
<script>
</script>
// 3.findIndex
<script>
</script>
(七) 扩展运算符 ...
知识点:
- 在对象中使用
- 在数组中使用
- 在函数中使用
1.在对象中使用
// 合并对象
const obj1 = {
a:2,
c:5
}
const obj2 = {
a:3,
b:4
}
// 合并两个对象
const obj = {
...obj1,
...obj2,
}
console.log(obj);
// 复制一个对象的同时修改或新增属性
const obj1 = {
name: 'zs',
age: 20
}
const obj2 = {
...obj1,
// 修改原来属性
age: 30,
// 新增属性
addr: '深圳'
}
console.log(obj2);
2. 在数组中使用
const arr1 = [1,2,3];
const arr2 = [
// 将arr1的所有成员放在这里
...arr1,
2,
4
]
console.log('arr2',arr2);
// 合并两个数组
const arr = [
...arr1,
...arr2
]
console.log('arr',arr)
3. 在函数中使用
const say = (a,b,...c)=> {
console.log(a,b,c)
}
say(1,2,3,4,5,6,7);
(八) Promise(背诵)
知识点:
- promise定义
- promise使用步骤
- async await异步变同步
- promise是异步编程的一种解决方案, 可以用来解决回调地狱的问题
(1) 什么是promise
promise中文意思承诺
promise有三种状态:
- pending 正在进行中
- resolved 成功
- rejected 失败
状态一旦改变,就无法再次改变状态,这也是它名字 promise-承诺 的由来,一个promise对象状态只能改变一次
我们可以使用promise来保存将来的数据
(2) promise的使用步骤
- 创建promise对象
- 存储成功或失败的数据
- 获取promise对象的数据
// promise例子
<!DOCTYPE html>
<html lang="en">
<body>
<script type="module">
let num = window.prompt("请输入数字");
// 1.创建promise对象
const obj = new Promise((resolve, reject) => {
// num > 10定位成功, 否则失败
if (num > 10) {
// 2.成功时用resolve保存数据
resolve({msg:'sucess',num});
} else {
// 3.失败时用reject保存数据
reject({ msg: 'error', num });
}
});
// 3.获取数据 then()获取成功的数据, catch()获取失败的数据
obj.then((res)=> {
console.log('成功', res);
}).catch(err=> {
console.log('失败',err);
})
</script>
</body>
</html>
// axios和Promise的关系
<!DOCTYPE html>
<html lang="en">
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.26.0/axios.min.js"></script>
<script>
const xhr = axios.get('xxxxx');
// axios.get()和axios.post() 都是返回一个Promise的实例对象
console.log(xhr instanceof Promise);
xhr.then(res=> {
console.log(res);
}).catch(err=> {
console.log(err);
})
</script>
</body>
</html>
(3) async await把异步变同步
01 一个小例子
<!DOCTYPE html>
<html lang="en">
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.26.0/axios.min.js"></script>
<script>
const getData = async () => {
try {
const res = await axios.get('http://huruqing.cn:3003/category/all2');
console.log(res.data);
} catch (error) {
console.log('错误信息',error);
}
}
getData();
</script>
</body>
</html>
02 实际应用
promise是异步编程的一种解决方案, 是为了解决回调地狱的问题(核心在于async await)
编程题: 根据提供的三个接口, 编写代码,找到广东分校web02班何秀英,并打印她的年龄
http://huruqing.cn:3009/getSchool 获取学校列表,无需参数
http://huruqing.cn:3009/getClass // 获取班级,需要schoolId
http://huruqing.cn:3009/getStudent // 获取学生对象, 需要参数classId
// 使用回调的方式解决(以前的方式)
<!DOCTYPE html>
<html lang="en">
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.26.0/axios.min.js"></script>
<script>
// 1.获取学校列表
axios.get('http://huruqing.cn:3009/getSchool').then(res => {
// schoolList 学校列表
let schoolList = res.data;
// 找到广东分校对应的编号
let schoolObj = schoolList.find(item => item.schoolName === '广东分校');
// 获取学校编号
let schoolId = schoolObj.schoolId;
// console.log('schoolId',schoolId);
axios.get('http://huruqing.cn:3009/getClass?schoolId=' + schoolId).then(res => {
let classList = res.data;
let classObj = classList.find(item => item.className === 'web02');
let classId = classObj.classId;
axios.get('http://huruqing.cn:3009/getStudent?classId=' + classId).then(res => {
// 学生列表
let studentList = res.data;
let studentObj = studentList.find(item => item.studentName === '何秀英');
console.log('何秀英的年龄是',studentObj.age);
}).catch(err => {
console.log('网络请求失败')
});
}).catch(err => {
console.log('网络请求失败');
});
}).catch(err => {
console.log('网络请求失败');
});
</script>
</body>
</html>
// 使用async await把异步变同步, 以上代码可以修如下
<!DOCTYPE html>
<html lang="en">
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.26.0/axios.min.js"></script>
<script>
async function getData() {
try {
// 获取学校编号
let schoolList = await axios.get('http://huruqing.cn:3009/getSchool');
let schoolObj = schoolList.find(item => item.schoolName === '广东分校');
let schoolId = schoolObj.schoolId;
// 获取班级编号
let classList = await axios.get('http://huruqing.cn:3009/getClass?schoolId=' + schoolId);
let classObj = classList.find(item => item.className === 'web02');
let classId = classObj.classId;
// 获取学生年龄
let studentList = await axios.get('http://huruqing.cn:3009/getStudent?classId=' + classId);
let studentList = res.data;
let studentObj = studentList.find(item => item.studentName === '何秀英');
console.log('何秀英的年龄是', studentObj.age);
} catch (error) {
console.log('网络请求失败', error);
}
}
</script>
</body>
</html>
(九) ES6 模块系统
在html中使用模块
<script type="module"></script>
(1) 常用模块化规范
就是制作一个js模块要遵守的原则
commonjs规范 nodejs遵守commonjs规范
AMD规范 reqire.js遵守AMD规范
CMD规范 sea.js遵守CMD规范(玉伯, 淘宝)
ES6模块化规范
(2) ES6模块导出和导入
1. 导出和导入方式(一)
// login.js登录模块,通过export导出模块
export let username = '张三';
export let age = 20;
// index.html 登入模块, script标签需要添加 type="module"
<!DOCTYPE html>
<html lang="en">
<body>
<script type="module">
// 通过import导入模块
import {
username,
age
} from "./login.js";
console.log(username);
console.log(age);
</script>
</body>
</html>
2. 导出和导入方式(二)
- 导出通过export default
- import xxx from 'xxx'
// login.js
export default {
username:"张三",
age:20,
};
// index.html
<!DOCTYPE html>
<html lang="en">
<body>
<script type="module">
import obj from "./login.js";
console.log(obj);
</script>
</body>
</html>
以上两种方式同时使用
// login.js
export let className = 'web1206';
export let teacher = '老胡';
export default {
username:"张三",
age:20,
};
// index.html
<!DOCTYPE html>
<html lang="en">
<body>
<script type="module">
// 获取到login.js里export default导出的数据
// import obj from "./login.js";
// console.log(obj);
// 获取到login.js里className和teacher的变量
// import {className,teacher} from './login.js';
// console.log(className,teacher);
// 合并写法
import obj,{className,teacher} from './login.js';
console.log(obj);
console.log(className,teacher);
</script>
</body>
</html>
3. 重命名
// login.js
export let className = 'web1206';
export let teacher = '老胡';
export let teacher2 = '老胡2';
export let teacher3 = '老胡3';
export let teacher4 = '老胡4';
export let teacher5 = '老胡5';
export let teacher6 = '老胡6';
// index.html
<!DOCTYPE html>
<html lang="en">
<body>
<script type="module">
// 使用as对变量进行重命名
import {className as c,teacher as t} from './login.js';
console.log(c,t);
// 把全部变量导入,保存在obj中
import * as obj from './login.js';
console.log(obj);
</script>
</body>
</html>
(十) class
es5没有class的概念
- 声明一个类
- 类继承
// es6的类, 用来创建对象
class Person{
// 构造器(其实就是es5里的构造函数)
constructor(nation) {
this.nation = nation;
this.type = '人类';
}
say() {
console.log(`这是一个${this.nation}人`);
}
sing() {
console.log('人类会唱歌');
}
}
// 定义一个女人的类
class Woman extends Person{
constructor(nation) {
// 调用父类构造器
super(nation);
this.sex = '女人';
}
}
var w = new Woman('中国');
console.log('国籍',w.nation);
console.log('类别',w.type);
w.sing();
(十一) 新类型(了解)
map
set
symble 可以创建独一无二的值
// map类型
const arr = [['name','zs'],['age',100]];
const map = new Map(arr);
// 获取数据
let name = map.get('name');
console.log(name);
// set
const arr = [1,2,3,4,2,1,56,2];
const set = new Set(arr);
// 将set转成数组
const arr2 = [...set];
console.log('arr2',arr2);
// symble
let key = 'aaa';
let key2 = 'aaa';
console.log(key === key2);
// 希望key和key2不相等
let x = Symbol('aa');
let y = Symbol('aa');
console.log(x === y);